package com.omni.monitor.plugin.threadpool;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.omni.monitor.model.threadpool.ThreadPoolStats;
import com.omni.monitor.model.threadpool.ThreadPoolStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 线程池策略管理（CRUD、规则解析、策略执行）
 */
@Slf4j
@Component
public class StrategyManager {
    // 策略存储（key：strategyId）
    private final Map<String, ThreadPoolStrategy> strategyMap = new ConcurrentHashMap<>();
    // 策略触发计数器（key：strategyId，value：连续满足条件次数）
    private final Map<String, Integer> triggerCounter = new ConcurrentHashMap<>();
    // 策略恢复计数器（key：strategyId，value：连续满足条件次数）
    private final Map<String, Integer> recoverCounter = new ConcurrentHashMap<>();
    // SpEL表达式解析器
    private final ExpressionParser spelParser = new SpelExpressionParser();
    // JSON解析器
    private final ObjectMapper objectMapper = new ObjectMapper();

    @PostConstruct
    public void init() {
        // 初始化默认策略（示例：全局高负载自动扩容）
        ThreadPoolStrategy defaultStrategy = new ThreadPoolStrategy();
        defaultStrategy.setStrategyId("DEFAULT_001");
        defaultStrategy.setPoolName("");
        defaultStrategy.setStrategyName("全局高负载扩容");
        defaultStrategy.setTriggerCondition("#activeThreadRatio>90 && #queueUsageRatio>70");
        defaultStrategy.setAdjustAction("{\"maximumPoolSize\":\"*1.5\",\"corePoolSize\":\"+5\"}");
        defaultStrategy.setRecoverCondition("#activeThreadRatio<30 && #queueUsageRatio<20");
        defaultStrategy.setRecoverAction("{\"maximumPoolSize\":\"*0.8\",\"corePoolSize\":\"-2\"}");
        defaultStrategy.setStatus(1);
        defaultStrategy.setTriggerDuration(3);
        defaultStrategy.setRecoverDuration(5);
        strategyMap.put(defaultStrategy.getStrategyId(), defaultStrategy);
        log.info("初始化默认线程池策略：{}", defaultStrategy.getStrategyName());
    }

    /**
     * 检查策略是否触发（核心方法）
     */
    public void checkAndExecuteStrategy(String poolName, ThreadPoolStats stats, ThreadPoolExecutor executor) {
        // 筛选适用于当前线程池的策略（全局策略+指定池策略）
        List<ThreadPoolStrategy> matchedStrategies = strategyMap.values().stream()
                .filter(s -> s.getStatus() == 1)
                .filter(s -> s.getPoolName().isEmpty() || s.getPoolName().equals(poolName)).collect(Collectors.toList());

        for (ThreadPoolStrategy strategy : matchedStrategies) {
            String strategyId = strategy.getStrategyId();
            // 1. 检查是否满足恢复条件
            if (evaluateCondition(strategy.getRecoverCondition(), stats)) {
                int count = recoverCounter.getOrDefault(strategyId, 0) + 1;
                if (count >= strategy.getRecoverDuration()) {
                    executeAdjustAction(strategy, executor, true);
                    recoverCounter.put(strategyId, 0); // 重置计数器
                    log.info("线程池[{}]策略[{}]触发恢复动作", poolName, strategy.getStrategyName());
                } else {
                    recoverCounter.put(strategyId, count);
                }
                continue;
            } else {
                recoverCounter.put(strategyId, 0); // 不满足恢复条件，重置计数器
            }

            // 2. 检查是否满足触发条件
            if (evaluateCondition(strategy.getTriggerCondition(), stats)) {
                int count = triggerCounter.getOrDefault(strategyId, 0) + 1;
                if (count >= strategy.getTriggerDuration()) {
                    executeAdjustAction(strategy, executor, false);
                    triggerCounter.put(strategyId, 0); // 重置计数器
                    log.info("线程池[{}]策略[{}]触发调整动作", poolName, strategy.getStrategyName());
                } else {
                    triggerCounter.put(strategyId, count);
                }
            } else {
                triggerCounter.put(strategyId, 0); // 不满足触发条件，重置计数器
            }
        }
    }

    /**
     * 解析并执行调整动作
     * @param isRecover 是否为恢复动作
     */
    private void executeAdjustAction(ThreadPoolStrategy strategy, ThreadPoolExecutor executor, boolean isRecover) {
        try {
            // 解析调整动作JSON（恢复动作优先用recoverAction，无则复用adjustAction）
            String actionJson = isRecover ?
                    (strategy.getRecoverAction() != null ? strategy.getRecoverAction() : strategy.getAdjustAction()) :
                    strategy.getAdjustAction();
            JsonNode actionNode = objectMapper.readTree(actionJson);

            // 处理核心线程数调整
            if (actionNode.has("corePoolSize")) {
                String coreAction = actionNode.get("corePoolSize").asText();
                int currentCore = executor.getCorePoolSize();
                int newCore = calculateNewValue(currentCore, coreAction);
                if (newCore >= 0 && newCore <= executor.getMaximumPoolSize()) {
                    executor.setCorePoolSize(newCore);
                    log.info("核心线程数调整：{} -> {}", currentCore, newCore);
                }
            }

            // 处理最大线程数调整
            if (actionNode.has("maximumPoolSize")) {
                String maxAction = actionNode.get("maximumPoolSize").asText();
                int currentMax = executor.getMaximumPoolSize();
                int newMax = calculateNewValue(currentMax, maxAction);
                // 最大线程数不超过CPU核心数×10（避免资源耗尽）
                int cpuCore = Runtime.getRuntime().availableProcessors();
                newMax = Math.min(newMax, cpuCore * 10);
                if (newMax >= executor.getCorePoolSize()) {
                    executor.setMaximumPoolSize(newMax);
                    log.info("最大线程数调整：{} -> {}", currentMax, newMax);
                }
            }

            // 处理队列容量调整（仅支持有界队列）
            if (actionNode.has("queueCapacity") && executor.getQueue() instanceof java.util.concurrent.ArrayBlockingQueue) {
                String queueAction = actionNode.get("queueCapacity").asText();
                int currentQueueCap = ((java.util.concurrent.ArrayBlockingQueue<?>) executor.getQueue()).size();
                int newQueueCap = calculateNewValue(currentQueueCap, queueAction);
                if (newQueueCap > 0) {
                    // 队列容量无法直接修改，需重建队列（此处简化处理，实际需结合业务场景）
                    log.warn("队列容量调整需重建队列，当前暂不支持自动重建，建议手动处理");
                }
            }

            // 更新策略最后执行时间
            strategy.setLastExecuteTime(new Date());
        } catch (JsonProcessingException e) {
            log.error("解析策略调整动作失败", e);
        }
    }

    /**
     * 计算调整后的值（支持 +N、-N、*N、/N 格式）
     */
    private int calculateNewValue(int currentValue, String action) {
        if (action.startsWith("+")) {
            return currentValue + Integer.parseInt(action.substring(1));
        } else if (action.startsWith("-")) {
            return currentValue - Integer.parseInt(action.substring(1));
        } else if (action.startsWith("*")) {
            return (int) (currentValue * Double.parseDouble(action.substring(1)));
        } else if (action.startsWith("/")) {
            return (int) (currentValue / Double.parseDouble(action.substring(1)));
        } else {
            return Integer.parseInt(action); // 直接指定值
        }
    }

    private boolean evaluateCondition(String condition, ThreadPoolStats stats) {
        // 第一层保障：stats本身不能为null（避免源头数据问题）
        if (stats == null) {
            log.error("评估SpEL条件失败：ThreadPoolStats对象为null，条件：{}", condition);
            return false;
        }
        if (condition == null || condition.isEmpty()) {
            log.warn("SpEL条件为空，跳过评估");
            return false;
        }

        try {
            Expression expression = spelParser.parseExpression(condition);
            EvaluationContext context = new StandardEvaluationContext();

            // ---------------------- 关键修复1：设置根对象为stats（避免根对象null） ----------------------
            // 即使表达式没加#，也能从stats中找到属性（双重保障）
            //context.setRootObject(stats);
            log.debug("SpEL根对象已设置为ThreadPoolStats，对象信息：{}", stats.toString());

            // ---------------------- 关键修复2：注入变量时显式加#前缀校验（可选，但推荐） ----------------------
            // 注入变量（保留原逻辑，确保变量可用）
            context.setVariable("activeThreadRatio", stats.getActiveThreadRatio());
            context.setVariable("queueUsageRatio", stats.getQueueUsageRatio());
            context.setVariable("taskCompletionRatio", stats.getTaskCompletionRatio());
            context.setVariable("rejectedCount", stats.getRejectedCount());
            context.setVariable("idleThreads", stats.getIdleThreads());

            // ---------------------- 关键修复3：检查表达式是否显式引用变量（加#），避免解析错位 ----------------------
            // 如果表达式包含变量名但没加#，打印警告（引导用户修正表达式）
            List<String> variableNames = Arrays.asList("activeThreadRatio", "queueUsageRatio", "taskCompletionRatio", "rejectedCount", "idleThreads");
            for (String varName : variableNames) {
                if (condition.contains(varName) && !condition.contains("#" + varName)) {
                    log.warn("SpEL表达式[{}]可能存在语法问题：引用变量{}时未加#前缀，建议改为#{}(避免解析为根对象属性)",
                            condition, varName, varName);
                }
            }

            // ---------------------- 调试日志：完整打印表达式和上下文 ----------------------
            log.debug("开始评估SpEL条件：{}", condition);
            log.debug("注入的变量列表：" +
                            "#activeThreadRatio={}, " +
                            "#queueUsageRatio={}, " +
                            "#taskCompletionRatio={}, " +
                            "#rejectedCount={}, " +
                            "#idleThreads={}",
                    stats.getActiveThreadRatio(),
                    stats.getQueueUsageRatio(),
                    stats.getTaskCompletionRatio(),
                    stats.getRejectedCount(),
                    stats.getIdleThreads()
            );

            // 执行表达式（强制从上下文解析，而非仅根对象）
            Object result = expression.getValue(context);
            if (result == null) {
                log.warn("SpEL条件[{}]执行结果为null，视为不满足", condition);
                return false;
            }
            if (!(result instanceof Boolean)) {
                log.error("SpEL条件[{}]执行结果类型错误（应为Boolean，实际为{}），视为不满足",
                        condition, result.getClass().getSimpleName());
                return false;
            }

            log.debug("SpEL条件[{}]评估结果：{}", condition, result);
            return (Boolean) result;

        } catch (Exception e) {
            // 增强异常日志：打印完整的条件、stats、表达式，方便定位
            log.error("评估SpEL条件失败！条件：{}，ThreadPoolStats：{}，错误详情：",
                    condition, stats.toString(), e);
            return false;
        }
    }

    // ---------------------- 策略CRUD方法（供Controller调用） ----------------------
    public List<ThreadPoolStrategy> getAllStrategies() {
        return new ArrayList<>(strategyMap.values());
    }

    public ThreadPoolStrategy getStrategyById(String strategyId) {
        return strategyMap.get(strategyId);
    }

    public void addStrategy(ThreadPoolStrategy strategy) {
        strategy.setStrategyId(strategy.getStrategyId() == null ? "STR_" + System.currentTimeMillis() : strategy.getStrategyId());
        strategy.setCreateTime(new Date());
        strategyMap.put(strategy.getStrategyId(), strategy);
        log.info("新增线程池策略：{}", strategy.getStrategyName());
    }

    public void updateStrategy(ThreadPoolStrategy strategy) {
        if (strategyMap.containsKey(strategy.getStrategyId())) {
            strategyMap.put(strategy.getStrategyId(), strategy);
            log.info("更新线程池策略：{}", strategy.getStrategyName());
        } else {
            throw new IllegalArgumentException("策略不存在：" + strategy.getStrategyId());
        }
    }

    public void deleteStrategy(String strategyId) {
        strategyMap.remove(strategyId);
        triggerCounter.remove(strategyId);
        recoverCounter.remove(strategyId);
        log.info("删除线程池策略：{}", strategyId);
    }
}